﻿using db_manage.dll.db;
using db_manage.model;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace db_manage.dll.manage
{
    /// <summary>
    /// 多任务执行各个数据库
    /// </summary>
    public partial class manage
    {
        //线程取消
        private static CancellationTokenSource _cancellationtokensource;
        //按服务器存放各个服务器的暂停控制
        private static readonly Dictionary<db_link_info, ManualResetEvent> _dic_manualresetevent = new Dictionary<db_link_info, ManualResetEvent>();
        private static List<db_link_info> _db_link_info;

        /// <summary>
        /// 多任务多数据库执行任务
        /// </summary>
        /// <param name="exec_action">执行任务</param>
        /// <param name="finished_action">所有任务完成后操作</param>
        /// <returns></returns>
        public static string db_task(req_db_task req)
        {
            //再次执行则取消之前的执行
            if (_cancellationtokensource != null && !_cancellationtokensource.IsCancellationRequested)
            {
                _cancellationtokensource.Cancel();
            }
            _cancellationtokensource = new CancellationTokenSource();

            var db_list = manage.db_info_list_get().Where(x => x.is_check)?.ToList();
            if (!(db_list?.Any() ?? false))
            {
                req?.finished_action?.Invoke();
                return "未勾选数据库";
            }

            //清空状态
            db_list.ForEach(x =>
            {
                x.updatestatus = null;
                x.remark = "";
            });

            //限制线程数量
            var max = db_manage_config.task_num;
            if (max > 0)
            {
                ThreadPool.SetMinThreads(1, 1);
                ThreadPool.SetMaxThreads(max, max);
            }

            //按服务器分组数据
            _db_link_info = db_list.Select(x => x.db_link_info).Distinct().ToList();
            _dic_manualresetevent.Clear();
            _db_link_info.ForEach(db_link_info =>
            {
                if (!_dic_manualresetevent.ContainsKey(db_link_info))
                {
                    _dic_manualresetevent.Add(db_link_info, new ManualResetEvent(true));
                }
            });

            var link_dic = new Dictionary<int, List<db_info>>();
            db_list.ForEach(x =>
            {
                var index = _db_link_info.IndexOf(x.db_link_info);
                if (!link_dic.ContainsKey(index))
                {
                    link_dic.Add(index, new List<db_info>());
                }
                link_dic[index].Add(x);
            });

            //任务入队列-按服务器顺序重新排序，防止一台服务器压力过大
            var queue_exec = new ConcurrentQueue<db_info>();
            var link_num = link_dic.Count();
            var max_db_num = link_dic.Select(x => x.Value.Count()).Max();
            for (var db_index = 0; db_index < max_db_num; db_index++)
            {
                for (var link_index = 0; link_index < link_num; link_index++)
                {
                    var now_db_list = link_dic[link_index];
                    if (now_db_list.Count() > db_index)
                    {
                        queue_exec.Enqueue(now_db_list[db_index]);
                    }
                }
            }

            var taskList = new List<Task>();
            while (!queue_exec.IsEmpty)
            {
                queue_exec.TryDequeue(out db_info now_db_info);
                var task = Task.Run(() =>
                {
                    //暂停控制
                    _dic_manualresetevent[now_db_info.db_link_info].WaitOne();
                    try
                    {
                        //初始化
                        now_db_info.updatetime = DateTime.Now;
                        now_db_info.remark = "未操作";
                        now_db_info.updatestatus = null;
                        now_db_info.taketime = 0;
                        now_db_info.vernum = null;

                        //启用连接
                        using var conn = db_factory.Instance.db_connection_fast_get(now_db_info);

                        //创建记录表
                        db_factory.Instance.db_record_create(now_db_info);

                        //执行
                        req.exec_action?.Invoke(now_db_info);
                    }
                    catch (Exception ex)
                    {
                        now_db_info.updatestatus = 0;
                        now_db_info.remark = ex.Message;
                    }
                }, _cancellationtokensource.Token);
                taskList.Add(task);
            }

            if (taskList.Any())
            {
                //全部完成后事件
                Task.WhenAll(taskList).ContinueWith((a) =>
                {
                    req.finished_action?.Invoke();
                });
            }
            return "操作已开启";
        }

        /// <summary>
        /// 设置服务器备份的启用和暂停
        /// </summary>
        /// <param name="db_link_info"></param>
        /// <param name="start_end"></param>
        public static void bak_start_end(db_link_info db_link_info, bool start_end)
        {
            var now_manualresetevent_list = _dic_manualresetevent.Where(x => x.Key == db_link_info || db_link_info == null)
                                                                ?.Select(x => x.Value)
                                                                ?.ToList();
            now_manualresetevent_list?.ForEach(now_manualresetevent =>
            {
                if (start_end)
                {
                    now_manualresetevent.Set();
                }
                else
                {
                    now_manualresetevent.Reset();
                }
            });
        }
    }
}
